using MediatR;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Services.Initial.Options;
using Serilog;
using Services.Initial.PublicProject.PublicClass.Basics;
using Services.InitialProject.Filters;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Data.SqlClient;
using Zack.ASPNETCore;
using Zack.Commons;
using Zack.Commons.JsonConverters;
using Zack.JWT;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
using Microsoft.Extensions.Hosting;
using Services.Initial.Filters;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using System.Reflection;
using FluentValidation;
using Services.Initial.PublicProject.PublicMethods;
using Services.InitialProject.Model;
using OpenTelemetry;
using SimpleRabbitmq;

namespace Services.Initial.Extensions;
public static class WebApplicationBuilderExtensions
{
    public static string ConnectionString => Environment.GetEnvironmentVariable("DefaultConnectionString")!;
    /// <summary>
    /// 配置使用数据库作为配置中心
    /// </summary>
    /// <param name="builder"></param>
    public static void ConfigureDbConfiguration(this WebApplicationBuilder builder)
    {
        // 使用polly重试策略
        PollyExtension.CreateRetryPolicy().ExecuteAndCapture(() =>
        {
                //使用数据库作为配置中心
                builder.Configuration.AddDbConfiguration(() => new SqlConnection(ConnectionString), reloadOnChange: true, reloadInterval: TimeSpan.FromSeconds(1));
        });   
    }
    public static void ConfigureExtraServices(this WebApplicationBuilder builder, InitializerOptions initOptions)
    {
        //var builder.Services = builder.Services;
        var config = builder.Configuration;
        var assmblies = ReflectionHelper.GetAllReferencedAssemblies();
        builder.Services.RunModuleInitializers(assmblies);
        builder.Services.AddAllDbContexts(ctx =>
        {
            ctx.UseSqlServer(ConnectionString);
        }, assmblies);
        //开始:Authentication,Authorization
        //只要需要校验Authentication报文头的地方（非IdentityService.WebAPI项目）也需要启用这些
        //IdentityService项目还需要启用AddIdentityCore
        builder.Services.AddAuthorization();
        //JWT
        builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(x =>
        {
            // 获取JWT配置信息
            JWTOptions jwtOpt = builder.Configuration.GetSection("JWT")!.Get<JWTOptions>()!;
            // 获取JWT秘钥
            byte[] keyBytes = Encoding.UTF8.GetBytes(jwtOpt.Key!);
            // 创建SymmetricSecurityKey
            var secKey = new SymmetricSecurityKey(keyBytes);
            // 设置TokenValidationParameters
            x.TokenValidationParameters = new()
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = jwtOpt.Issuer,
                ValidAudience = jwtOpt.Audience,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOpt.Key))
            };
            x.Events = new JwtBearerEvents
            {
                OnMessageReceived = context =>
                {
                    var accessToken = context.Request.Query["access_token"];
                    var path = context.Request.Path;
                    if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/Hubs/ChatRoomHub"))
                    {
                        context.Token = accessToken;
                    }
                    return Task.CompletedTask;
                }
            };
        });
        // 配置智谱清言Apikey
        builder.Services.Configure<ZhiPuQingYan>(config.GetSection("ZhiPuQingYan"));
        // 配置jwt
        var jwtOptions = config.GetSection("JWT").Get<JWTOptions>();
        //builder.Services.AddJWTAuthentication(jwtOptions!);
        //启用Swagger中的【Authorize】按钮。这样就不用每个项目的AddSwaggerGen中单独配置了
        builder.Services.Configure<SwaggerGenOptions>(o =>
        {
            o.AddAuthenticationHeader();
        });
        //添加mediatr
        builder.Services.AddMediatR(assmblies);
        //配置唯一工作单元
        builder.Services.Configure<MvcOptions>(o =>
        {
            o.Filters.Add<ExceptionFilter>();
            o.Filters.Add<UnitOfWorkFilter>();
            o.Filters.Add<ValidatorFilter>();
        });
        //配种json中的日期格式
        builder.Services.Configure<JsonOptions>(o =>
        {
            o.JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss"));
        });
        //配置跨域
        builder.Services.AddCors(o =>
        {
            var corsOptions = config.GetSection("Cors").Get<CorsOptions>();
            o.AddDefaultPolicy(builder =>
            {
                //builder.WithOrigins(corsOptions!.Origins!).AllowAnyHeader().AllowAnyMethod().AllowCredentials();
                builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
            });
        });
        const string OUTPUT_TEMPLATE = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}";
        //配置日志
        builder.Services.AddLogging(logBuilder =>
        {
            Log.Logger = new LoggerConfiguration().MinimumLevel.Debug().WriteTo.Console().WriteTo.File(initOptions.LogFilePath, rollingInterval: RollingInterval.Day, outputTemplate: OUTPUT_TEMPLATE).CreateLogger();
            logBuilder.AddSerilog();
        });
        builder.Host.UseSerilog();
        //配置FluentValidation 使用自动验证难以自动以返回值类型，那么就直接使用手动验证 及在每一个方法体中手动调用方法验证 
        //builder.Services.AddFluentValidationAutoValidation(x=>x.).AddFluentValidationClientsideAdapters().AddValidatorsFromAssemblies(assmblies);
        //注册jwt
        builder.Services.Configure<JWTOptions>(config.GetSection("JWT"));
        //注册eventbus rabbitmq
        //builder.Services.Configure<IntegrationEventRabbitMQOptions>(config.GetSection("RabbitMQ"));
        //builder.Services.AddEventBus(initOptions.EventBusQueueName, assmblies);
        builder.EventConfiguration("myRabbitmq", "myExchange");
        //builder.AddRabbitMQ("myRabbitmq");
        //配置redis
        // var redisString = config.GetValue<string>("Redis:ConnStr");
        // var redisConnMultiplexer = ConnectionMultiplexer.Connect(redisString);
        // builder.Services.AddSingleton(typeof(IConnectionMultiplexer), redisConnMultiplexer);
        builder.AddRedisOutputCache("myRedis");
        //配置 ASP.NET Core 以使用代理服务器和负载均衡器
        builder.Services.Configure<ForwardedHeadersOptions>(opt =>
        {
            opt.ForwardedHeaders = Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.All;
        });
        //注册返回httresponse服务
        builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        //注册aspire服务
        builder.Services.AddProblemDetails();
        builder.ConfigureOpenTelemetry();
        builder.AddDefaultHealthChecks();
        builder.Services.AddServiceDiscovery();
        builder.Services.ConfigureHttpClientDefaults(http =>
        {
            // Turn on resilience by default
            http.AddStandardResilienceHandler();

            // Turn on service discovery by default
           // http.UseServiceDiscovery();
        });
        //添加验证器
        builder.AddValidationServices();
        //添加控制器
        builder.Services.AddControllers().AddNewtonsoftJson();
        //添加HttpClientFactory
        builder.Services.AddHttpClient();
        BaseHttpContext.ServiceCollection = builder.Services;
    }
    public static IHostApplicationBuilder ConfigureOpenTelemetry(this WebApplicationBuilder builder)
    {
        builder.Logging.AddOpenTelemetry(logging =>
        {
            logging.IncludeFormattedMessage = true;
            logging.IncludeScopes = true;
        });

        builder.Services.AddOpenTelemetry()
            .WithMetrics(metrics =>
            {
                metrics.AddAspNetCoreInstrumentation()
                    .AddHttpClientInstrumentation()
                    .AddRuntimeInstrumentation();
            })
            .WithTracing(tracing =>
            {
                tracing.AddAspNetCoreInstrumentation()
                    // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package)
                    //.AddGrpcClientInstrumentation()
                    .AddHttpClientInstrumentation();
            });

        builder.AddOpenTelemetryExporters();

        return builder;
    }

    private static IHostApplicationBuilder AddOpenTelemetryExporters(this WebApplicationBuilder builder)
    {
        var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);

        if (useOtlpExporter)
        {
            builder.Services.AddOpenTelemetry().UseOtlpExporter();
        }

        // Uncomment the following lines to enable the Prometheus exporter (requires the OpenTelemetry.Exporter.Prometheus.AspNetCore package)
        // builder.Services.AddOpenTelemetry()
        //    .WithMetrics(metrics => metrics.AddPrometheusExporter());

        // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.Exporter package)
        // builder.Services.AddOpenTelemetry()
        //    .UseAzureMonitor();

        return builder;
    }

    public static IHostApplicationBuilder AddDefaultHealthChecks(this WebApplicationBuilder builder)
    {
        builder.Services.AddHealthChecks()
            // Add a default liveness check to ensure app is responsive
            .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);

        return builder;
    }

    private static MeterProviderBuilder AddBuiltInMeters(this MeterProviderBuilder meterProviderBuilder) =>
        meterProviderBuilder.AddMeter(
            "Microsoft.AspNetCore.Hosting",
            "Microsoft.AspNetCore.Server.Kestrel",
            "System.Net.Http");

    private static void AddValidationServices(this WebApplicationBuilder builder)
    {
        //使用反射获取所有的验证器并注册
        var types = Assembly.GetEntryAssembly()!.GetTypes();
        foreach (var type in types)
        {
            // 如果类型是验证器
            if (type.IsAssignableTo(typeof(IValidator)))
            {
                var validatorType = type.GetInterfaces()
                    .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IValidator<>));
                if (validatorType != null)
                {
                    var genericType = validatorType.GetGenericArguments()[0];
                    builder.Services.AddTransient(typeof(IValidator<>).MakeGenericType(genericType), type);
                }
            }
        }
    }
}